package com.k.kpp.web.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.util.StringUtils;
import com.k.kpp.web.easyexcel2.annotation.ExcelDynamicSelectService;
import com.k.kpp.web.easyexcel2.annotation.ExcelHeaderFormat;
import com.k.kpp.web.easyexcel2.annotation.ExcelSelected;
import com.k.kpp.web.easyexcel2.annotation.ExcelSelectedResolve;
import com.k.kpp.web.easyexcel2.handler.ExcelDropDownHandler;
import com.k.kpp.web.easyexcel2.handler.HeaderFormatHandler;
import com.k.kpp.web.easyexcel2.handler.I18nCellWriteHandler;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.*;

/**
 * utils
 *
 * @author ljw
 */
@Slf4j
public class EasyExcelUtils {
    public static <T> void genTemplate(OutputStream output, Class<T> clazz, Map<Integer, String[]> dropDownMap,
                                       String sheetName) {
        try {
            Map<Integer, ExcelSelectedResolve> dropDownResolve = null;
            if (dropDownMap == null || dropDownMap.isEmpty()) {
                // dropDownMap = resolveSelectedAnnotation(clazz);
                dropDownResolve = resolveSelectedAnnotation(clazz);
            }
            EasyExcel.write(output, clazz).head(clazz).registerWriteHandler(new I18nCellWriteHandler())
                    .registerWriteHandler(new ExcelDropDownHandler(dropDownResolve)).sheet(sheetName)
                    .doWrite(Collections.emptyList());
        } catch (Exception e) {
            log.error("export arrive point data error", e);
        } finally {
            if (null != output) {
                try {
                    output.close();
                } catch (IOException ioe) {
                    log.error("export template,close outputStream error", ioe);
                }
            }
        }
    }

    public static <T> void genTemplate(OutputStream output, Class<T> clazz, Map<Integer, String[]> dropDownMap,
                                       String sheetName, Properties headFormatProp) {
        try {
            Map<Integer, ExcelSelectedResolve> dropDownResolve = null;
            if (dropDownMap == null || dropDownMap.isEmpty()) {
                dropDownResolve = resolveSelectedAnnotation(clazz);
            }
            if (Objects.isNull(headFormatProp)) {
                headFormatProp = resolveHeadFormat(clazz);
            }
            EasyExcel.write(output, clazz).head(clazz).registerWriteHandler(new HeaderFormatHandler(headFormatProp))
                    .registerWriteHandler(new I18nCellWriteHandler())
                    .registerWriteHandler(new ExcelDropDownHandler(dropDownResolve)).sheet(sheetName)
                    .doWrite(Collections.emptyList());
        } catch (Exception e) {
            log.error("export arrive point data error", e);
        } finally {
            if (null != output) {
                try {
                    output.close();
                } catch (IOException ioe) {
                    log.error("export template,close outputStream error", ioe);
                }
            }
        }
    }

    public static <T> void exportExcel(OutputStream output, Class<T> clazz, String sheetName, Collection<?> data) {
        try {
            Properties headFormatProp = resolveHeadFormat(clazz);
            EasyExcel.write(output, clazz).head(clazz).registerWriteHandler(new HeaderFormatHandler(headFormatProp))
                    .sheet(sheetName).doWrite(data);
        } catch (Exception e) {
            log.error("export arrive point data error", e);
        } finally {
            if (null != output) {
                try {
                    output.close();
                } catch (IOException ioe) {
                    log.error("export arrive point data,close outputStream error", ioe);
                }
            }
        }
    }

    private static <T> Properties resolveHeadFormat(Class<T> clazz) {
        ExcelHeaderFormat formatClazz = clazz.getAnnotation(ExcelHeaderFormat.class);
        String[] headSource = null;
        if (formatClazz != null) {
            headSource = formatClazz.source();
            if (headSource.length > 0) {
                return buildHeaderProp(headSource);
            }
            Class<? extends ExcelDynamicSelectService> classes = formatClazz.sourceClass()[0];
            try {
                ExcelDynamicSelectService c = classes.newInstance();
                headSource = c.getSource();

            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return buildHeaderProp(headSource);
    }

    private static Properties buildHeaderProp(String[] arr) {
        Properties p = new Properties();
        if (arr != null && arr.length > 0) {
            for (String str : arr) {
                String[] pair = str.split(":");
                if (pair.length == 2) {
                    p.setProperty(pair[0], pair[1]);
                }
            }
        }
        return p;
    }

    private static <T> Map<Integer, ExcelSelectedResolve> resolveSelectedAnnotation(Class<T> head) {
        Map<Integer, ExcelSelectedResolve> selectedMap = new HashMap<>();
        Field[] fields = head.getDeclaredFields();
        for (int i = 0; i < fields.length; ++i) {
            Field field = fields[i];
            ExcelSelected selected = field.getAnnotation(ExcelSelected.class);
            ExcelProperty property = field.getAnnotation(ExcelProperty.class);
            if (selected != null) {
                ExcelSelectedResolve excelSelectedResolve = new ExcelSelectedResolve();
                String[] source = resolveSelectedSource(selected);
                if (source != null && source.length > 0) {
                    excelSelectedResolve.setSource(source);
                    excelSelectedResolve.setFirstRow(selected.firstRow());
                    excelSelectedResolve.setLastRow(selected.lastRow());
                    if (property != null && property.index() >= 0) {
                        selectedMap.put(property.index(), excelSelectedResolve);
                    } else {
                        selectedMap.put(i, excelSelectedResolve);
                    }
                }
            }
        }
        return selectedMap;
    }

    public static String[] resolveSelectedSource(ExcelSelected excelSelected) {
        String[] resolveSource = new String[]{};
        if (excelSelected == null) {
            return resolveSource;
        } else {
            String[] source = excelSelected.source();
            if (source.length > 0) {
                return source;
            } else {
                Class<? extends ExcelDynamicSelectService>[] classes = excelSelected.sourceClass();
                if (classes.length > 0) {
                    try {
                        ExcelDynamicSelectService excelDynamicSelectService = classes[0].newInstance();
                        String methodParams = excelSelected.methodParams();
                        if (StringUtils.isEmpty(methodParams)) {
                            resolveSource = excelDynamicSelectService.getSource();
                        } else {
                            resolveSource = excelDynamicSelectService.getSource(methodParams);
                        }
                        if (resolveSource != null && resolveSource.length > 0) {
                            return resolveSource;
                        }
                    } catch (IllegalAccessException | InstantiationException var9) {
                        log.error("Excel dropdown error:", var9);
                    }
                }
                return resolveSource;
            }
        }
    }
}
